﻿/*
 * scadahis.cpp
 *
 *  Created on: 2017年7月10日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_SCADA DM_API_EXPORT

#include <dm/scada/scadahis.hpp>

#include <dm/os/log/logger.hpp>
#include <dm/os/db/db.hpp>
#include <dm/os/db/resultset.hpp>
#include <dm/datetime.hpp>
#include <dm/timestamp.hpp>
#include <cstdio>
#include <dm/env/cfg.hpp>

namespace dm{
namespace scada{

static const char* logModule = "CScadaHis.scada.dm";

static const char* r_status = "r_status";
static const char* r_discrete = "r_discrete";
static const char* r_measure = "r_measure";
static const char* r_cumulant = "r_cumulant";
static const char* r_action = "r_action";

// 数据查询时，使用集合视图
// 产生集合视图的工具应该主动对各月份表数据增加初始值和结束值，并设置自动原因
static const char* v_status = "v_status";
static const char* v_discrete = "v_discrete";
static const char* v_measure = "v_measure";
static const char* v_cumulant = "v_cumulant";
static const char* v_action = "v_action";

static inline void setTableNameByYear( char* table,const char* pre,const dm::CDateTime& dt ){
	std::sprintf(table,"%s%04d",pre,dt.year());
}

static inline void setTableNameByMonth( char* table,const char* pre,const dm::CDateTime& dt ){
	std::sprintf(table,"%s%04d%02d",pre,dt.year(),dt.month());
}

static inline void setTableNameByDay( char* table,const char* pre,const dm::CDateTime& dt ){
	std::sprintf(table,"%s%04d%02d%02d",pre,dt.year(),dt.month(),dt.day());
}

static inline void setTableNameByHour( char* table,const char* pre,const dm::CDateTime& dt ){
	std::sprintf(table,"%s%04d%02d%02d%02d",pre,dt.year(),dt.month(),dt.day(),dt.hour());
}

static inline void setTableNameByMinute( char* table,const char* pre,const dm::CDateTime& dt ){
	std::sprintf(table,"%s%04d%02d%02d%02d%02d",pre,dt.year(),dt.month(),dt.day(),dt.hour(),dt.minute());
}

static inline void setTableName( void (*f)(char*,const char*,const dm::CDateTime&),char* tableThis,char* tableLast,char* tableNext,const char* pre,
		const dm::CTimeStamp::s_t& thisSecs,const dm::CTimeStamp::s_t& lastSecs,const dm::CTimeStamp::s_t& nextSecs ){
	f(tableThis,pre,dm::CDateTime(dm::CTimeStamp(thisSecs,0)));
	f(tableLast,pre,dm::CDateTime(dm::CTimeStamp(lastSecs,0)));
	f(tableNext,pre,dm::CDateTime(dm::CTimeStamp(nextSecs,0)));
}

///////////////////////////////////

CScadaHis::CScadaHis(){
	log().debug(THISMODULE "创建对象");

	dm::env::CCfg& cfg = dm::env::CCfg::ins();

	m_db = dm::os::createDb(cfg.his_dbName().c_str(),cfg.his_dbHost().c_str(),cfg.his_dbEngine().c_str());
	if( !m_db->connect(cfg.his_dbUsr().c_str(),cfg.his_dbPwd().c_str()) ){
		log().error(THISMODULE "连接历史数据库失败");
	}

	m_mtType = MtNone;
	refresh(dm::CTimeStamp::cur());
}

CScadaHis& CScadaHis::ins(){
	static CScadaHis i;
	return i;
}

CScadaHis::~CScadaHis(){
}

bool CScadaHis::connect(){
	if( m_db->isConnected() )
		return true;
	dm::env::CCfg& cfg = dm::env::CCfg::ins();

	return m_db->connect(cfg.his_dbUsr().c_str(),cfg.his_dbPwd().c_str());
}

void CScadaHis::tryUnlock(){
#ifdef DB_SQLITE
	m_db->disconnect();
#endif
}

/**
 * 添加状态量记录
 * 记录添加到相应的时标表中。如果使用影子表，则添加到影子表中。
 * @param rcd
 */
void CScadaHis::appendStatus( const SHisRcdStatus& rcd ){
	char value[24];
	sprintf(value,"%5d",rcd.v);

	if( !append(m_tableLastStatus,m_tableThisStatus,m_tableNextStatus,rcd.name,value,rcd.ts,rcd.op,rcd.cause) )
		log().warnning(THISMODULE "添加记录失败");
}

void CScadaHis::appendDiscrete( const SHisRcdDiscrete& rcd ){
	char value[24];
	sprintf(value,"%5d",rcd.v);

	if( !append(m_tableLastDiscrete,m_tableThisDiscrete,m_tableNextDiscrete,rcd.name,value,rcd.ts,rcd.op,rcd.cause) )
		log().warnning(THISMODULE "添加记录失败");
}

void CScadaHis::appendMeasure( const SHisRcdMeasure& rcd ){
	char value[24];
	sprintf(value,"%.5f",rcd.v);

	if( !append(m_tableLastMeasure,m_tableThisMeasure,m_tableNextMeasure,rcd.name,value,rcd.ts,rcd.op,rcd.cause) )
		log().warnning(THISMODULE "添加记录失败");
}

void CScadaHis::appendCumulant( const SHisRcdCumulant& rcd ){
	char value[24];
	sprintf(value,"%f",rcd.v);

	if( !append(m_tableLastCumulant,m_tableThisCumulant,m_tableNextCumulant,rcd.name,value,rcd.ts,rcd.op,rcd.cause) )
		log().warnning(THISMODULE "添加记录失败");
}

void CScadaHis::appendAction( const SHisRcdAction& rcd ){
	char value[24];
	sprintf(value,"%d",rcd.v);

	if( !append(m_tableLastAction,m_tableThisAction,m_tableNextAction,rcd.name,value,rcd.ts,rcd.op,rcd.cause) )
		log().warnning(THISMODULE "添加记录失败");
}

/**
 * 更新查询
 * 根据数据库内的记录表重新构建查询视图
 * @return 是否成功
 */
bool CScadaHis::updateQuery(){
	// 获取所有状态量表
#ifdef DB_MYSQL
#else

#endif
	return false;
}

bool CScadaHis::getBeginOfStatus( dm::CTimeStamp& ts,const char* name ){
	return getBegin(ts,v_status,name);
}

bool CScadaHis::getBeginOfDiscrete( dm::CTimeStamp& ts,const char* name ){
	return getBegin(ts,v_discrete,name);
}

bool CScadaHis::getBeginOfMeasure( dm::CTimeStamp& ts,const char* name ){
	return getBegin(ts,v_measure,name);
}

bool CScadaHis::getBeginOfCumulant( dm::CTimeStamp& ts,const char* name ){
	return getBegin(ts,v_cumulant,name);
}

bool CScadaHis::getBeginOfAction( dm::CTimeStamp& ts,const char* name ){
	return getBegin(ts,v_action,name);
}

bool CScadaHis::getEndOfStatus( dm::CTimeStamp& ts,const char* name ){
	return getEnd(ts,v_status,name);
}

bool CScadaHis::getEndOfDiscrete( dm::CTimeStamp& ts,const char* name ){
	return getEnd(ts,v_discrete,name);
}

bool CScadaHis::getEndOfMeasure( dm::CTimeStamp& ts,const char* name ){
	return getEnd(ts,v_measure,name);
}

bool CScadaHis::getEndOfCumulant( dm::CTimeStamp& ts,const char* name ){
	return getEnd(ts,v_cumulant,name);
}

bool CScadaHis::getEndOfAction( dm::CTimeStamp& ts,const char* name ){
	return getEnd(ts,v_action,name);
}

bool CScadaHis::getFirstStatus( SHisRcdStatus& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,true,rcd.name.c_str());
	return getRecordStatus(rcd,condition);
}

bool CScadaHis::getFirstDiscrete( SHisRcdDiscrete& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,true,rcd.name.c_str());
	return getRecordDiscrete(rcd,condition);
}

bool CScadaHis::getFirstMeasure( SHisRcdMeasure& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,true,rcd.name.c_str());
	return getRecordMeasure(rcd,condition);
}

bool CScadaHis::getFirstCumulant( SHisRcdCumulant& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,true,rcd.name.c_str());
	return getRecordCumulant(rcd,condition);
}

bool CScadaHis::getFirstAction( SHisRcdAction& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,true,rcd.name.c_str());
	return getRecordAction(rcd,condition);
}

bool CScadaHis::getLastStatus( SHisRcdStatus& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,false,rcd.name.c_str());
	return getRecordStatus(rcd,condition);
}

bool CScadaHis::getLastDiscrete( SHisRcdDiscrete& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,false,rcd.name.c_str());
	return getRecordDiscrete(rcd,condition);
}

bool CScadaHis::getLastMeasure( SHisRcdMeasure& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,false,rcd.name.c_str());
	return getRecordMeasure(rcd,condition);
}

bool CScadaHis::getLastCumulant( SHisRcdCumulant& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,false,rcd.name.c_str());
	return getRecordCumulant(rcd,condition);
}

bool CScadaHis::getLastAction( SHisRcdAction& rcd ){
	char condition[256];
	getFirstOrLastCondition(condition,false,rcd.name.c_str());
	return getRecordAction(rcd,condition);
}

bool CScadaHis::getNextStatus( SHisRcdStatus& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,false,rcd.name.c_str());
	return getRecordStatus(rcd,condition);
}

bool CScadaHis::getNextDiscrete( SHisRcdDiscrete& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,false,rcd.name.c_str());
	return getRecordDiscrete(rcd,condition);
}

bool CScadaHis::getNextMeasure( SHisRcdMeasure& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,false,rcd.name.c_str());
	return getRecordMeasure(rcd,condition);
}

bool CScadaHis::getNextCumulant( SHisRcdCumulant& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,false,rcd.name.c_str());
	return getRecordCumulant(rcd,condition);
}

bool CScadaHis::getNextAction( SHisRcdAction& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,false,rcd.name.c_str());
	return getRecordAction(rcd,condition);
}

bool CScadaHis::getPreviousStatus( SHisRcdStatus& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,true,rcd.name.c_str());
	return getRecordStatus(rcd,condition);
}

bool CScadaHis::getPreviousDiscrete( SHisRcdDiscrete& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,true,rcd.name.c_str());
	return getRecordDiscrete(rcd,condition);
}

bool CScadaHis::getPreviousMeasure( SHisRcdMeasure& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,true,rcd.name.c_str());
	return getRecordMeasure(rcd,condition);
}

bool CScadaHis::getPreviousCumulant( SHisRcdCumulant& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,true,rcd.name.c_str());
	return getRecordCumulant(rcd,condition);
}

bool CScadaHis::getPreviousAction( SHisRcdAction& rcd ){
	char condition[256];
	getPreviousOrNextCondition(condition,rcd.ts,true,rcd.name.c_str());
	return getRecordAction(rcd,condition);
}

bool CScadaHis::statusAt( const name_t& name,const dm::CTimeStamp& ts,CStatus::value_t& v ){
	char condition[256];
	getAtCondition(condition,ts,name.c_str());
	SHisRcdStatus rcd;
	if(! getRecordStatus(rcd,condition) )
		return false;
	v = rcd.v;
	return true;
}

bool CScadaHis::discreteAt( const name_t& name,const dm::CTimeStamp& ts,CDiscrete::value_t& v ){
	char condition[256];
	getAtCondition(condition,ts,name.c_str());
	SHisRcdDiscrete rcd;
	if(! getRecordDiscrete(rcd,condition) )
		return false;
	v = rcd.v;
	return true;
}

bool CScadaHis::measureAt( const name_t& name,const dm::CTimeStamp& ts,CMeasure::value_t& v ){
	char condition[256];
	getAtCondition(condition,ts,name.c_str());
	SHisRcdMeasure rcd;
	if(! getRecordMeasure(rcd,condition) )
		return false;
	v = rcd.v;
	return true;
}

bool CScadaHis::cumulantAt( const name_t& name,const dm::CTimeStamp& ts,CCumulant::value_t& v ){
	char condition[256];
	getAtCondition(condition,ts,name.c_str());
	SHisRcdCumulant rcd;
	if(! getRecordCumulant(rcd,condition) )
		return false;
	v = rcd.v;
	return true;
}

bool CScadaHis::actionAt( const name_t& name,const dm::CTimeStamp& ts,CAction::value_t& v ){
	char condition[256];
	getAtCondition(condition,ts,name.c_str());
	SHisRcdAction rcd;
	if(! getRecordAction(rcd,condition) )
		return false;
	v = rcd.v;
	return true;
}

int CScadaHis::getStatusCount( const char* name ){
	return getCount(v_status,name);
}

int CScadaHis::getDiscreteCount( const char* name ){
	return getCount(v_discrete,name);
}

int CScadaHis::getMeasureCount( const char* name ){
	return getCount(v_measure,name);
}

int CScadaHis::getCumulantCount( const char* name ){
	return getCount(v_cumulant,name);
}

int CScadaHis::getActionCount( const char* name ){
	return getCount(v_action,name);
}

int CScadaHis::getStatusCountBefore( const dm::CTimeStamp& ts,const char* name ){
	return getCountBefore(ts,v_status,name);
}

int CScadaHis::getDiscreteCountBefore( const dm::CTimeStamp& ts,const char* name ){
	return getCountBefore(ts,v_discrete,name);
}

int CScadaHis::getMeasureCountBefore( const dm::CTimeStamp& ts,const char* name ){
	return getCountBefore(ts,v_measure,name);
}

int CScadaHis::getCumulantCountBefore( const dm::CTimeStamp& ts,const char* name ){
	return getCountBefore(ts,v_cumulant,name);
}

int CScadaHis::getActionCountBefore( const dm::CTimeStamp& ts,const char* name ){
	return getCountBefore(ts,v_action,name);
}

int CScadaHis::getStatusCountAfter( const dm::CTimeStamp& ts,const char* name ){
	return getCountAfter(ts,v_status,name);
}

int CScadaHis::getDiscreteCountAfter( const dm::CTimeStamp& ts,const char* name ){
	return getCountAfter(ts,v_discrete,name);
}

int CScadaHis::getMeasureCountAfter( const dm::CTimeStamp& ts,const char* name ){
	return getCountAfter(ts,v_measure,name);
}

int CScadaHis::getCumulantCountAfter( const dm::CTimeStamp& ts,const char* name ){
	return getCountAfter(ts,v_cumulant,name);
}

int CScadaHis::getActionCountAfter( const dm::CTimeStamp& ts,const char* name ){
	return getCountAfter(ts,v_action,name);
}

int CScadaHis::getStatusCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name ){
	return getCountBetween(tsBegin,tsEnd,v_status,name);
}

int CScadaHis::getDiscreteCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name ){
	return getCountBetween(tsBegin,tsEnd,v_discrete,name);
}

int CScadaHis::getMeasureCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name ){
	return getCountBetween(tsBegin,tsEnd,v_measure,name);
}

int CScadaHis::getCumulantCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name ){
	return getCountBetween(tsBegin,tsEnd,v_cumulant,name);
}

int CScadaHis::getActionCount( const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name ){
	return getCountBetween(tsBegin,tsEnd,v_action,name);
}

void CScadaHis::clearStatus( const char* name ){
	clear(v_status,name);
}

void CScadaHis::clearDiscrete( const char* name ){
	clear(v_discrete,name);
}

void CScadaHis::clearMeasure( const char* name ){
	clear(v_measure,name);
}

void CScadaHis::clearCumulant( const char* name ){
	clear(v_cumulant,name);
}

void CScadaHis::clearAction( const char* name ){
	clear(v_action,name);
}

void CScadaHis::clearStatusBefore( const dm::CTimeStamp& ts,const char* name ){
	clearBefore(ts,v_status,name);
}

void CScadaHis::clearDiscreteBefore( const dm::CTimeStamp& ts,const char* name ){
	clearBefore(ts,v_discrete,name);
}

void CScadaHis::clearMeasureBefore( const dm::CTimeStamp& ts,const char* name ){
	clearBefore(ts,v_measure,name);
}

void CScadaHis::clearCumulantBefore( const dm::CTimeStamp& ts,const char* name ){
	clearBefore(ts,v_cumulant,name);
}

void CScadaHis::clearActionBefore( const dm::CTimeStamp& ts,const char* name ){
	clearBefore(ts,v_action,name);
}

void CScadaHis::clearStatusBeforeAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearBeforeAndComplement(ts,v_status,name);
}

void CScadaHis::clearDiscreteBeforeAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearBeforeAndComplement(ts,v_discrete,name);
}

void CScadaHis::clearMeasureBeforeAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearBeforeAndComplement(ts,v_measure,name);
}

void CScadaHis::clearCumulantBeforeAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearBeforeAndComplement(ts,v_cumulant,name);
}

void CScadaHis::clearActionBeforeAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearBeforeAndComplement(ts,v_action,name);
}

void CScadaHis::clearStatusAfter( const dm::CTimeStamp& ts,const char* name ){
	clearAfter(ts,v_status,name);
}

void CScadaHis::clearDiscreteAfter( const dm::CTimeStamp& ts,const char* name ){
	clearAfter(ts,v_discrete,name);
}

void CScadaHis::clearMeasureAfter( const dm::CTimeStamp& ts,const char* name ){
	clearAfter(ts,v_measure,name);
}

void CScadaHis::clearCumulantAfter( const dm::CTimeStamp& ts,const char* name ){
	clearAfter(ts,v_cumulant,name);
}

void CScadaHis::clearActionAfter( const dm::CTimeStamp& ts,const char* name ){
	clearAfter(ts,v_action,name);
}

void CScadaHis::clearStatusAfterAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearAfterAndComplement(ts,v_status,name);
}

void CScadaHis::clearDiscreteAfterAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearAfterAndComplement(ts,v_discrete,name);
}

void CScadaHis::clearMeasureAfterAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearAfterAndComplement(ts,v_measure,name);
}

void CScadaHis::clearCumulantAfterAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearAfterAndComplement(ts,v_cumulant,name);
}

void CScadaHis::clearActionAfterAndComplement( const dm::CTimeStamp& ts,const char* name ){
	clearAfterAndComplement(ts,v_action,name);
}

bool CScadaHis::getStatus( const name_t& name,status_his_t& d ){
	char condition[256];
	sprintf(condition,"name='%s'",name.c_str());
	return getRecordsStatus(d,condition);
}

bool CScadaHis::getStatusBefore( const dm::CTimeStamp& ts,status_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts);
	return getRecordsStatus(d,condition);
}

bool CScadaHis::getStatusBefore( const name_t& name,const dm::CTimeStamp& ts,status_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts,name.c_str());
	return getRecordsStatus(d,condition);
}

bool CScadaHis::getStatusAfter( const dm::CTimeStamp& ts,status_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts);
	return getRecordsStatus(d,condition);
}

bool CScadaHis::getStatusAfter( const name_t& name,const dm::CTimeStamp& ts,status_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts,name.c_str());
	return getRecordsStatus(d,condition);
}

bool CScadaHis::getStatusBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,status_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e);
	return getRecordsStatus(d,condition);
}

bool CScadaHis::getStatusBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,status_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e,name.c_str());
	return getRecordsStatus(d,condition);
}

////////////////
bool CScadaHis::getDiscrete( const name_t& name,discrete_his_t& d ){
	char condition[256];
	sprintf(condition,"name='%s'",name.c_str());
	return getRecordsDiscrete(d,condition);
}

bool CScadaHis::getDiscreteBefore( const dm::CTimeStamp& ts,discrete_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts);
	return getRecordsDiscrete(d,condition);
}

bool CScadaHis::getDiscreteBefore( const name_t& name,const dm::CTimeStamp& ts,discrete_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts,name.c_str());
	return getRecordsDiscrete(d,condition);
}

bool CScadaHis::getDiscreteAfter( const dm::CTimeStamp& ts,discrete_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts);
	return getRecordsDiscrete(d,condition);
}

bool CScadaHis::getDiscreteAfter( const name_t& name,const dm::CTimeStamp& ts,discrete_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts,name.c_str());
	return getRecordsDiscrete(d,condition);
}

bool CScadaHis::getDiscreteBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,discrete_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e);
	return getRecordsDiscrete(d,condition);
}

bool CScadaHis::getDiscreteBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,discrete_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e,name.c_str());
	return getRecordsDiscrete(d,condition);
}

////////////////////
bool CScadaHis::getMeasure( const name_t& name,measure_his_t& d ){
	char condition[256];
	sprintf(condition,"name='%s'",name.c_str());
	return getRecordsMeasure(d,condition);
}

bool CScadaHis::getMeasureBefore( const dm::CTimeStamp& ts,measure_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts);
	return getRecordsMeasure(d,condition);
}

bool CScadaHis::getMeasureBefore( const name_t& name,const dm::CTimeStamp& ts,measure_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts,name.c_str());
	return getRecordsMeasure(d,condition);
}

bool CScadaHis::getMeasureAfter( const dm::CTimeStamp& ts,measure_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts);
	return getRecordsMeasure(d,condition);
}

bool CScadaHis::getMeasureAfter( const name_t& name,const dm::CTimeStamp& ts,measure_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts,name.c_str());
	return getRecordsMeasure(d,condition);
}

bool CScadaHis::getMeasureBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,measure_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e);
	return getRecordsMeasure(d,condition);
}

bool CScadaHis::getMeasureBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,measure_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e,name.c_str());
	return getRecordsMeasure(d,condition);
}

///////////
bool CScadaHis::getCumulant( const name_t& name,cumulant_his_t& d ){
	char condition[256];
	sprintf(condition,"name='%s'",name.c_str());
	return getRecordsCumulant(d,condition);
}

bool CScadaHis::getCumulantBefore( const dm::CTimeStamp& ts,cumulant_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts);
	return getRecordsCumulant(d,condition);
}

bool CScadaHis::getCumulantBefore( const name_t& name,const dm::CTimeStamp& ts,cumulant_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts,name.c_str());
	return getRecordsCumulant(d,condition);
}

bool CScadaHis::getCumulantAfter( const dm::CTimeStamp& ts,cumulant_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts);
	return getRecordsCumulant(d,condition);
}

bool CScadaHis::getCumulantAfter( const name_t& name,const dm::CTimeStamp& ts,cumulant_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts,name.c_str());
	return getRecordsCumulant(d,condition);
}

bool CScadaHis::getCumulantBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,cumulant_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e);
	return getRecordsCumulant(d,condition);
}

bool CScadaHis::getCumulantBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,cumulant_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e,name.c_str());
	return getRecordsCumulant(d,condition);
}

/////////////////////////
bool CScadaHis::getAction( const name_t& name,action_his_t& d ){
	char condition[256];
	sprintf(condition,"name='%s'",name.c_str());
	return getRecordsAction(d,condition);
}

bool CScadaHis::getActionBefore( const dm::CTimeStamp& ts,action_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts);
	return getRecordsAction(d,condition);
}

bool CScadaHis::getActionBefore( const name_t& name,const dm::CTimeStamp& ts,action_his_t& d ){
	char condition[256];
	conditionBefore(condition,ts,name.c_str());
	return getRecordsAction(d,condition);
}

bool CScadaHis::getActionAfter( const dm::CTimeStamp& ts,action_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts);
	return getRecordsAction(d,condition);
}

bool CScadaHis::getActionAfter( const name_t& name,const dm::CTimeStamp& ts,action_his_t& d ){
	char condition[256];
	conditionAfter(condition,ts,name.c_str());
	return getRecordsAction(d,condition);
}

bool CScadaHis::getActionBetween( const dm::CTimeStamp& s,const dm::CTimeStamp& e,action_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e);
	return getRecordsAction(d,condition);
}

bool CScadaHis::getActionBetween( const name_t& name,const dm::CTimeStamp& s,const dm::CTimeStamp& e,action_his_t& d ){
	char condition[256];
	conditionBetween(condition,s,e,name.c_str());
	return getRecordsAction(d,condition);
}

/**
 * 将字符串转换成时标
 * @param tsString
 * @param ts
 */
bool CScadaHis::string2timeStmp( const char* tsString,dm::CTimeStamp& ts ){
	dm::CDateTime dt;
	if( !dt.fromString(tsString) )
		return false;

	dt.toTimeStamp(ts);

	return true;
}

/**
 * 将时标转换成字符串
 * @param ts
 * @param str
 */
void CScadaHis::timeStmp2string( const dm::CTimeStamp& ts,char* str ){
	dm::CDateTime dt = ts;
	std::sprintf(str,"%04d-%02d-%02d %02d:%02d:%02d.%d",dt.year(),dt.month(),dt.day(),dt.hour(),dt.minute(),dt.sec(),dt.msec());
}

void CScadaHis::setTableNames( void (*f)(char*,const char*,const dm::CDateTime&) ){
	setTableName(f,
			m_tableThisStatus.str(),m_tableLastStatus.str(),m_tableNextStatus.str(),r_status,
			m_thisSecs,m_lastSecs,m_nextSecs);
	setTableName(f,
			m_tableThisDiscrete.str(),m_tableLastDiscrete.str(),m_tableNextDiscrete.str(),r_discrete,
			m_thisSecs,m_lastSecs,m_nextSecs);
	setTableName(f,
			m_tableThisMeasure.str(),m_tableLastMeasure.str(),m_tableNextMeasure.str(),r_measure,
			m_thisSecs,m_lastSecs,m_nextSecs);
	setTableName(f,
			m_tableThisCumulant.str(),m_tableLastCumulant.str(),m_tableNextCumulant.str(),r_cumulant,
			m_thisSecs,m_lastSecs,m_nextSecs);
	setTableName(f,
			m_tableThisAction.str(),m_tableLastAction.str(),m_tableNextAction.str(),r_action,
			m_thisSecs,m_lastSecs,m_nextSecs);
}

bool CScadaHis::append( const table_name_t& tableLast,const table_name_t& tableThis,const table_name_t& tableNext,const name_t& name,const char* value,const dm::CTimeStamp& dts,const dm::CTimeStamp& ots,const int& cause ){
	if( m_mtType==MtNone ){
		return append(tableThis.c_str(),name,value,dts,ots,cause);
	}else{
		if( dts.seconds()>=m_futureSecs ){
			log().warnning(THISMODULE "不合理的时标。记录时标%d(%s)未来时段%d(%s)",dts.seconds(),dm::CDateTime(dts).toString().c_str(),
					m_futureSecs,dm::CDateTime(dm::CTimeStamp(m_futureSecs,0)).toString().c_str());
			return false;
		}else if( dts.seconds()>=m_nextSecs ){
			return append(tableNext.c_str(),name,value,dts,ots,cause);
		}else if( dts.seconds()>=m_thisSecs ){
			return append(tableThis.c_str(),name,value,dts,ots,cause);
		}else if( dts.seconds()>=m_lastSecs ){
			return append(tableLast.c_str(),name,value,dts,ots,cause);
		}else{
			log().warnning(THISMODULE "不合理的时标。记录时标%d(%s)早于上时间段%d(%s)",dts.seconds(),dm::CDateTime(dts).toString().c_str(),
					m_lastSecs,dm::CDateTime(dm::CTimeStamp(m_lastSecs,0)).toString().c_str());
			return false;
		}
	}
}

/**
 * 添加记录到表中
 * @param table
 * @param name
 * @param value
 * @param dts
 * @param ots
 * @param cause
 * @return
 */
bool CScadaHis::append( const char* table,const name_t& name,const char* value,const dm::CTimeStamp& dts,const dm::CTimeStamp& ots,const int& cause ){
	char otsStr[32];

	timeStmp2string(ots,otsStr);

	char sql[1024];
#ifdef DB_MYSQL
	sprintf(sql,"insert into %s(name,value,dts_s,dts_ms,ots,cause) values('%s',%s,%ld,%d,timestamp('%s',3),%d)",table,name.c_str(),value,dts.seconds(),dts.mseconds(),otsStr,cause);
#else
	sprintf(sql,"insert into %s(name,value,dts_s,dts_ms,ots,cause) values('%s',%s,%ld,%d,'%s',%d)",table,name.c_str(),value,dts.seconds(),dts.mseconds(),otsStr,cause);
#endif

	return m_db->exec(sql);
}

bool CScadaHis::getTimeStamp( dm::CTimeStamp& ts,const char* table,const char* asc,const char* name ){
	char sql[1024];
	if( name )
		sprintf(sql,"select dts_s,dts_ms from %s where name='%s' and cause!=0 order by dts_s %s,dts_ms %s LIMIT 1",table,name,asc,asc);
	else
		sprintf(sql,"select dts_s,dts_ms from %s where cause!=0 order by dts_s %s,dts_ms %s LIMIT 1",table,asc,asc);

	resultset_p rs(m_db->query(sql));
	if( !rs || !rs->next() )
		return false;

	ts.setSeconds(rs->asInt64(0));
	ts.setMseconds(rs->asInt(1));

	return true;
}

bool CScadaHis::getRecord( resultset_p& rs,const char* table,const char* condition ){
	char sql[1024];

#ifdef DB_MYSQL
	sprintf(sql,"select name,value,dts_s,dts_ms,ots,cause from %s where cause!=0 and %s",table,condition);
#else
	sprintf(sql,"select name,value,dts_s,dts_ms,strftime('%%Y-%%m-%%d %%H:%%M:%%S.%%f',ots),cause from %s where cause!=0 and %s",table,condition);
#endif

	rs = m_db->query(sql);
	if( !rs || !rs->next() ){
		log().debug(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::getRecordStatus( SHisRcdStatus& rcd,const char* condition ){
	resultset_p rs;
	if( !getRecord(rs,v_status,condition) )
		return false;

	rcd.name = rs->asString(0);
	rcd.v = rs->asInt(1);
	rcd.ts.setSeconds(rs->asInt64(2));
	rcd.ts.setMseconds(rs->asInt(3));
	string2timeStmp(rs->asString(4).c_str(),rcd.op);
	rcd.cause = (SHisRcdStatus::ECause)rs->asInt(5);

	return true;
}

bool CScadaHis::getRecordDiscrete( SHisRcdDiscrete& rcd,const char* condition ){
	resultset_p rs;
	if( !getRecord(rs,v_discrete,condition) )
		return false;

	rcd.name = rs->asString(0);
	rcd.v = rs->asInt(1);
	rcd.ts.setSeconds(rs->asInt64(2));
	rcd.ts.setMseconds(rs->asInt(3));
	string2timeStmp(rs->asString(4).c_str(),rcd.op);
	rcd.cause = (SHisRcdDiscrete::ECause)rs->asInt(5);

	return true;
}

bool CScadaHis::getRecordMeasure( SHisRcdMeasure& rcd,const char* condition ){
	resultset_p rs;
	if( !getRecord(rs,v_measure,condition) )
		return false;

	rcd.name = rs->asString(0);
	rcd.v = rs->asDouble(1);
	rcd.ts.setSeconds(rs->asInt64(2));
	rcd.ts.setMseconds(rs->asInt(3));
	string2timeStmp(rs->asString(4).c_str(),rcd.op);
	rcd.cause = (SHisRcdMeasure::ECause)rs->asInt(5);

	return true;
}

bool CScadaHis::getRecordCumulant( SHisRcdCumulant& rcd,const char* condition ){
	resultset_p rs;
	if( !getRecord(rs,v_cumulant,condition) )
		return false;

	rcd.name = rs->asString(0);
	rcd.v = rs->asDouble(1);
	rcd.ts.setSeconds(rs->asInt64(2));
	rcd.ts.setMseconds(rs->asInt(3));
	string2timeStmp(rs->asString(4).c_str(),rcd.op);
	rcd.cause = (SHisRcdCumulant::ECause)rs->asInt(5);

	return true;
}

bool CScadaHis::getRecordAction( SHisRcdAction& rcd,const char* condition ){
	resultset_p rs;
	if( !getRecord(rs,v_action,condition) )
		return false;

	rcd.name = rs->asString(0);
	rcd.v = rs->asUint(1);
	rcd.ts.setSeconds(rs->asInt64(2));
	rcd.ts.setMseconds(rs->asInt(3));
	string2timeStmp(rs->asString(4).c_str(),rcd.op);
	rcd.cause = (SHisRcdAction::ECause)rs->asInt(5);

	return true;
}

bool CScadaHis::getRecords( resultset_p& rs,const char* table,const char* condition ){
	char sql[1024];

	if( condition ){
#ifdef DB_MYSQL
	sprintf(sql,"select name,value,dts_s,dts_ms,ots,cause from %s where cause!=0 and %s ORDER BY dts_s,dts_ms",table,condition);
#else
	sprintf(sql,"select name,value,dts_s,dts_ms,strftime('%%Y-%%m-%%d %%H:%%M:%%S.%%f',ots),cause from %s where cause!=0 and %s ORDER BY dts_s,dts_ms",table,condition);
#endif
	}else{
#ifdef DB_MYSQL
	sprintf(sql,"select name,value,dts_s,dts_ms,ots,cause from %s where cause!=0 ORDER BY dts",table);
#else
	sprintf(sql,"select name,value,dts_s,dts_ms,strftime('%%Y-%%m-%%d %%H:%%M:%%S.%%f',ots),cause from %s where cause!=0 ORDER BY dts_s,dts_ms",table);
#endif
	}

	rs = m_db->query(sql);
	if( !rs ){
		log().debug(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::getRecordsStatus( status_his_t& d,const char* condition ){
	resultset_p rs;
	if( !getRecords(rs,v_status,condition) ){
		return false;
	}

	d.reset(rs->size());
	for( int i=0;i<d.count();++i ){
		if( !rs->next() ){
			log().error(THISMODULE "结果集大小不一致 i=%d,size=%d",i,d.count());
			return false;
		}
		d[i].name = rs->asString(0);
		d[i].v = rs->asUint(1);
		d[i].ts.setSeconds(rs->asInt64(2));
		d[i].ts.setMseconds(rs->asInt(3));
		string2timeStmp(rs->asString(4).c_str(),d[i].op);
		d[i].cause = (SHisRcdStatus::ECause)rs->asInt(5);
	}

	return true;
}

bool CScadaHis::getRecordsDiscrete( discrete_his_t& d,const char* condition ){
	resultset_p rs;
	if( !getRecords(rs,v_discrete,condition) ){
		return false;
	}

	d.reset(rs->size());
	for( int i=0;i<d.count();++i ){
		if( !rs->next() ){
			log().error(THISMODULE "结果集大小不一致 i=%d,size=%d",i,d.count());
			return false;
		}
		d[i].name = rs->asString(0);
		d[i].v = rs->asUint(1);
		d[i].ts.setSeconds(rs->asInt64(2));
		d[i].ts.setMseconds(rs->asInt(3));
		string2timeStmp(rs->asString(4).c_str(),d[i].op);
		d[i].cause = (SHisRcdDiscrete::ECause)rs->asInt(5);
	}

	return true;
}

bool CScadaHis::getRecordsMeasure( measure_his_t& d,const char* condition ){
	resultset_p rs;
	if( !getRecords(rs,v_measure,condition) ){
		return false;
	}

	d.reset(rs->size());
	for( int i=0;i<d.count();++i ){
		if( !rs->next() ){
			log().error(THISMODULE "结果集大小不一致 i=%d,size=%d",i,d.count());
			return false;
		}
		d[i].name = rs->asString(0);
		d[i].v = rs->asDouble(1);
		d[i].ts.setSeconds(rs->asInt64(2));
		d[i].ts.setMseconds(rs->asInt(3));
		string2timeStmp(rs->asString(4).c_str(),d[i].op);
		d[i].cause = (SHisRcdMeasure::ECause)rs->asInt(5);
	}

	return true;
}

bool CScadaHis::getRecordsCumulant( cumulant_his_t& d,const char* condition ){
	resultset_p rs;
	if( !getRecords(rs,v_cumulant,condition) ){
		return false;
	}

	d.reset(rs->size());
	for( int i=0;i<d.count();++i ){
		if( !rs->next() ){
			log().error(THISMODULE "结果集大小不一致 i=%d,size=%d",i,d.count());
			return false;
		}
		d[i].name = rs->asString(0);
		d[i].v = rs->asDouble(1);
		d[i].ts.setSeconds(rs->asInt64(2));
		d[i].ts.setMseconds(rs->asInt(3));
		string2timeStmp(rs->asString(4).c_str(),d[i].op);
		d[i].cause = (SHisRcdCumulant::ECause)rs->asInt(5);
	}

	return true;
}

bool CScadaHis::getRecordsAction( action_his_t& d,const char* condition ){
	resultset_p rs;
	if( !getRecords(rs,v_action,condition) ){
		return false;
	}

	d.reset(rs->size());
	for( int i=0;i<d.count();++i ){
		if( !rs->next() ){
			log().error(THISMODULE "结果集大小不一致 i=%d,size=%d",i,d.count());
			return false;
		}
		d[i].name = rs->asString(0);
		d[i].v = rs->asUint(1);
		d[i].ts.setSeconds(rs->asInt64(2));
		d[i].ts.setMseconds(rs->asInt(3));
		string2timeStmp(rs->asString(4).c_str(),d[i].op);
		d[i].cause = (SHisRcdAction::ECause)rs->asInt(5);
	}

	return true;
}

void CScadaHis::getFirstOrLastCondition( char* condition,bool first,const char* name ){
	if( name ){
		if( first )
			sprintf(condition,"name='%s' order by dts_s ASC,dts_ms ASC LIMIT 1",name);
		else
			sprintf(condition,"name='%s' order by dts_s DESC,dts_ms DESC LIMIT 1",name);
	}else{
		if( first )
			sprintf(condition,"1=1 order by dts_s ASC,dts_ms ASC LIMIT 1");
		else
			sprintf(condition,"1=1 order by dts_s DESC,dts_ms DESC LIMIT 1");
	}
}

void CScadaHis::getPreviousOrNextCondition( char* condition,const dm::CTimeStamp& ts,bool previous,const char* name ){
	char c[256];
	if( previous ){
		conditionTs(c,ts,"<",name);
		sprintf(condition,"%s order by dts_s DESC,dts_ms DESC LIMIT 1",c);
	}else{
		conditionTs(c,ts,">",name);
		sprintf(condition,"%s order by dts_s ASC,dts_ms ASC LIMIT 1",c);
	}
}

void CScadaHis::getAtCondition( char* condition,const dm::CTimeStamp& ts,const char* name ){
	char c[256];
	conditionTs(c,ts,"<=",name);
	sprintf(condition,"%s order by dts_s DESC,dts_ms DESC LIMIT 1",c);
}

int CScadaHis::getCountByCondition( const char* table,const char* condition ){
	char sql[64];

	if(condition)
		sprintf(sql,"select count(*) from %s where %s",table,condition);
	else
		sprintf(sql,"select count(*) from %s",table);

	resultset_p rs(m_db->query(sql));
	if( rs && rs->next() )
		return rs->asInt(0);
	return -1;
}

int CScadaHis::getCount( const char* table,const char* name ){
	if( name ){
		char condition[256];
		sprintf(condition,"name='%s'",name);
		return getCountByCondition(table,condition);
	}else
		return getCountByCondition(table);
}

void CScadaHis::clear( const char* type,const dm::CTimeStamp& ts,const char* table,const char* name ){
	char sql[1024];

	char condition[256];
	conditionTs(condition,ts,type,name);

	sprintf(sql,"delete from %s where %s",table,condition);
	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
	}
}

void CScadaHis::clearAndComplement( const char* type,const char* typeCp,const dm::CTimeStamp& ts,const char* table,const char* name ){
	char sql[1024];

	char otsStr[32];
	timeStmp2string(dm::CTimeStamp::cur(),otsStr);

	char condition[256];
	conditionTs(condition,ts,typeCp,name);

	sprintf(sql,"INSERT OR IGNORE INTO %s(name,value,dts_s,dts_ms,ots,cause) SELECT name,value,%ld,%d,'%s',4 from %s where %s ORDER BY dts_s,dts_ms DESC",
			table,ts.seconds(),ts.mseconds(),otsStr,table,condition);
	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
	}

	conditionTs(condition,ts,type,name);
	sprintf(sql,"delete from %s where %s",table,condition);

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
	}
}

void CScadaHis::clear( const char* table,const char* name ){
	char sql[64];
	if( name )
		sprintf(sql,"delete from %s where name='%s'",table,name);
	else
		sprintf(sql,"delete from %s",table);

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
	}
}

bool CScadaHis::createIfStatus( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow ){
	if( !createIfStatus(lastMonth) )
		return false;
	if( !createIfStatus(thisMonth) )
		return false;
	if( !createIfStatus(nextMonth) )
		return false;

#ifdef DB_MYSQL
	if( !createIfStatusShadow(lastMonthShadow) )
		return false;
	if( !createIfStatusShadow(thisMonthShadow) )
		return false;
	if( !createIfStatusShadow(nextMonthShadow) )
		return false;
#endif

	return true;
}

bool CScadaHis::createIfDiscrete( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow ){
	if( !createIfDiscrete(lastMonth) )
		return false;
	if( !createIfDiscrete(thisMonth) )
		return false;
	if( !createIfDiscrete(nextMonth) )
		return false;

#ifdef DB_MYSQL
	if( !createIfDiscreteShadow(lastMonthShadow) )
		return false;
	if( !createIfDiscreteShadow(thisMonthShadow) )
		return false;
	if( !createIfDiscreteShadow(nextMonthShadow) )
		return false;
#endif

	return true;
}

bool CScadaHis::createIfMeasure( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow ){
	if( !createIfMeasure(lastMonth) )
		return false;
	if( !createIfMeasure(thisMonth) )
		return false;
	if( !createIfMeasure(nextMonth) )
		return false;

#ifdef DB_MYSQL
	if( !createIfStatusShadow(lastMonthShadow) )
		return false;
	if( !createIfStatusShadow(thisMonthShadow) )
		return false;
	if( !createIfStatusShadow(nextMonthShadow) )
		return false;
#endif

	return true;
}

bool CScadaHis::createIfCumulant( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow ){
	if( !createIfCumulant(lastMonth) )
		return false;
	if( !createIfCumulant(thisMonth) )
		return false;
	if( !createIfCumulant(nextMonth) )
		return false;

#ifdef DB_MYSQL
	if( !createIfCumulantShadow(lastMonthShadow) )
		return false;
	if( !createIfCumulantShadow(thisMonthShadow) )
		return false;
	if( !createIfCumulantShadow(nextMonthShadow) )
		return false;
#endif

	return true;
}

bool CScadaHis::createIfAction( const char* lastMonth,const char* lastMonthShadow,const char* thisMonth,const char* thisMonthShadow,const char* nextMonth,const char* nextMonthShadow ){
	if( !createIfAction(lastMonth) )
		return false;
	if( !createIfAction(thisMonth) )
		return false;
	if( !createIfAction(nextMonth) )
		return false;

#ifdef DB_MYSQL
	if( !createIfActionShadow(lastMonthShadow) )
		return false;
	if( !createIfActionShadow(thisMonthShadow) )
		return false;
	if( !createIfActionShadow(nextMonthShadow) )
		return false;
#endif

	return true;
}

bool CScadaHis::createIfStatus( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value int(2) NOT NULL, dts_s int(20) NOT NULL comment '时标秒', dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL, cause int(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms)) comment='状态量记录'",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value integer(2) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif
	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}
	return true;
}

bool CScadaHis::createIfStatusShadow( const char* table ){
	char sql[512];
#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value int(2) NOT NULL, dts_s int(20) NOT NULL comment '时标秒', dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL, cause int(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))ENGINE=MEMORY comment='状态量记录'",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value integer(2) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif
	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfDiscrete( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value int(11) NOT NULL, dts_s int(20) NOT NULL, dts_ms int(6) NOT NULL comment '数据时标毫秒', ots timestamp(3) NOT NULL, cause int(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value integer(11) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfDiscreteShadow( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value int(11) NOT NULL, dts_s int(20) NOT NULL, dts_ms int(6) NOT NULL comment '数据时标毫秒', ots timestamp(3) NOT NULL, cause int(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))ENGINE=MEMORY",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value integer(11) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfMeasure( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float NOT NULL, dts_s int(20) NOT NULL comment '数据时标', dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL comment '操作时标', cause int(11) NOT NULL comment '记录原因', PRIMARY KEY (name, dts_s, dts_ms)) comment='测量值记录表'",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float(10) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfMeasureShadow( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float NOT NULL, dts_s int(20) NOT NULL comment '数据时标', dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL comment '操作时标', cause int(11) NOT NULL comment '记录原因', PRIMARY KEY (name, dts_s, dts_ms))ENGINE=MEMORY comment='测量值记录表'",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float(10) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfCumulant( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float NOT NULL, dts_s int(20) NOT NULL comment '数据时标', dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL comment '操作时标', cause int(11) NOT NULL comment '记录原因', PRIMARY KEY (name, dts_s, dts_ms)) comment='测量值记录表'",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float(10) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfCumulantShadow( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float NOT NULL, dts_s int(20) NOT NULL comment '数据时标', dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL comment '操作时标', cause int(11) NOT NULL comment '记录原因', PRIMARY KEY (name, dts_s, dts_ms))ENGINE=MEMORY comment='测量值记录表'",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value float(10) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfAction( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value int(2) NOT NULL, dts_s int(20) NOT NULL, dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL, cause int(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value integer(2) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}

	return true;
}

bool CScadaHis::createIfActionShadow( const char* table ){
	char sql[512];

#ifdef DB_MYSQL
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value int(2) NOT NULL, dts_s int(20) NOT NULL, dts_ms int(6) NOT NULL, ots timestamp(3) NOT NULL, cause int(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))ENGINE=MEMORY",table);
#else
	sprintf(sql,"CREATE TABLE IF NOT EXISTS %s(name varchar(64) NOT NULL, value integer(2) NOT NULL, dts_s integer(20) NOT NULL, dts_ms integer(6) NOT NULL, ots timestamp NOT NULL, cause integer(11) NOT NULL, PRIMARY KEY (name, dts_s, dts_ms))",table);
#endif

	if( !m_db->exec(sql) ){
		log().warnning(THISMODULE "失败 %s",sql);
		return false;
	}
	return true;
}

/**
 * 更新状态量
 * @return
 */
bool CScadaHis::updateQuery_status(){
	resultset_p rs(m_db->getTables("r_status%"));
	if( !rs ){
		log().warnning(THISMODULE "获取表信息失败");
		return false;
	}

	std::string tables;
	if( rs->next() ){
		tables = rs->asString(0);
		while( rs->next() ){
			tables += ",";
			tables += rs->asString(0);
		}
	}

	return false;
}

void CScadaHis::conditionBetween( char* condition,const dm::CTimeStamp& tsBegin,const dm::CTimeStamp& tsEnd,const char* name ){
	if( name ){
		sprintf(condition,"name='%s' and (dts_s>%ld or (dts_s=%ld and dts_ms>=%d)) and (dts_s<%ld or (dts_s=%ld and dts_ms<=%d))",name,
			tsBegin.seconds(),tsBegin.seconds(),tsBegin.mseconds(),
			tsEnd.seconds(),tsEnd.seconds(),tsEnd.mseconds());
	}else{
		sprintf(condition,"(dts_s>%ld or (dts_s=%ld and dts_ms>=%d)) and (dts_s<%ld or (dts_s=%ld and dts_ms<=%d))",
					tsBegin.seconds(),tsBegin.seconds(),tsBegin.mseconds(),
					tsEnd.seconds(),tsEnd.seconds(),tsEnd.mseconds());
	}
}

void CScadaHis::conditionTs( char* condition,const dm::CTimeStamp& ts,const char* type,const char* name ){
	if( strcmp(type,"<")==0 ){
		if( name )
			sprintf(condition,"name='%s' and (dts_s<%ld or (dts_s=%ld and dts_ms<%d))",name,ts.seconds(),ts.seconds(),ts.mseconds());
		else
			sprintf(condition,"dts_s<%ld or (dts_s=%ld and dts_ms<%d)",ts.seconds(),ts.seconds(),ts.mseconds());
	}else if( strcmp(type,"<=")==0 ){
		if( name )
			sprintf(condition,"name='%s' and (dts_s<%ld or (dts_s=%ld and dts_ms<=%d))",name,ts.seconds(),ts.seconds(),ts.mseconds());
		else
			sprintf(condition,"dts_s<%ld or (dts_s=%ld and dts_ms<=%d)",ts.seconds(),ts.seconds(),ts.mseconds());
	}else if( strcmp(type,"=")==0 ){
		if( name )
			sprintf(condition,"name='%s' and dts_s=%ld and dts_ms=%d",name,ts.seconds(),ts.mseconds());
		else
			sprintf(condition,"dts_s=%ld and dts_ms=%d",ts.seconds(),ts.mseconds());
	}else if( strcmp(type,">=")==0 ){
		if( name )
			sprintf(condition,"name='%s' and (dts_s>%ld or (dts_s=%ld and dts_ms>=%d))",name,ts.seconds(),ts.seconds(),ts.mseconds());
		else
			sprintf(condition,"dts_s>%ld or (dts_s=%ld and dts_ms>=%d)",ts.seconds(),ts.seconds(),ts.mseconds());
	}else if( strcmp(type,">")==0 ){
		if( name )
			sprintf(condition,"name='%s' and (dts_s>%ld or (dts_s=%ld and dts_ms>%d))",name,ts.seconds(),ts.seconds(),ts.mseconds());
		else
			sprintf(condition,"dts_s>%ld or (dts_s=%ld and dts_ms>%d)",ts.seconds(),ts.seconds(),ts.mseconds());
	}
}

/**
 * 判断数据库表是否存在
 * @param table
 * @return
 */
bool CScadaHis::ifTable( const char* table ){
	char sql[512];
#ifdef DB_MYSQL
	sprintf(sql,"select count(*) from infomation_schema.tables where table_schema='dm_his' and table_type='BASE TABLE' and table_name='%s'",table);
#else
	sprintf(sql,"select count(*) from sqlite_master where type='table' and tbl_name='%s'",table);
#endif
	resultset_p rs(m_db->query(sql));
	if( rs && rs->next() )
		return rs->asInt(0)==1;
	return false;
}

void CScadaHis::dropTable( const char* table ){
	char sql[512];
	sprintf(sql,"drop table %s",table);
	m_db->exec(sql);
}

void CScadaHis::dropIfTable( const char* table ){
	char sql[512];
	sprintf(sql,"drop table if exist %s",table);
	m_db->exec(sql);
}

void CScadaHis::setMultiTableType( const EMultiTable& type ){
	m_mtType = type;
}

/**
 * 刷新表格
 * @param now
 */
bool CScadaHis::refresh( const dm::CTimeStamp& now ){
	switch( m_mtType ){
	case MtNone:
		break;
	case MtMinute:
		m_thisSecs = now.seconds() - (now.seconds()%60);
		m_lastSecs = m_thisSecs - 60;
		m_nextSecs = m_thisSecs + 60;
		m_futureSecs = m_nextSecs + 60;

		setTableNames(setTableNameByMinute);
		break;
	case Mt2Minutes:
		m_thisSecs = now.seconds() - (now.seconds()%(60*2));
		m_lastSecs = m_thisSecs - 60*2;
		m_nextSecs = m_thisSecs + 60*2;
		m_futureSecs = m_nextSecs + 60*2;

		setTableNames(setTableNameByMinute);
		break;
	case Mt5Minutes:
		m_thisSecs = now.seconds() - (now.seconds()%(60*5));
		m_lastSecs = m_thisSecs - 60*5;
		m_nextSecs = m_thisSecs + 60*5;
		m_futureSecs = m_nextSecs + 60*5;

		setTableNames(setTableNameByMinute);
		break;
	case Mt10Minutes:
		m_thisSecs = now.seconds() - (now.seconds()%(60*10));
		m_lastSecs = m_thisSecs - 60*10;
		m_nextSecs = m_thisSecs + 60*10;
		m_futureSecs = m_nextSecs + 60*10;

		setTableNames(setTableNameByMinute);
		break;
	case Mt20Minutes:
		m_thisSecs = now.seconds() - (now.seconds()%(60*20));
		m_lastSecs = m_thisSecs - 60*20;
		m_nextSecs = m_thisSecs + 60*20;
		m_futureSecs = m_nextSecs + 60*20;

		setTableNames(setTableNameByMinute);
		break;
	case Mt30Minutes:
		m_thisSecs = now.seconds() - (now.seconds()%(60*30));
		m_lastSecs = m_thisSecs - 60*30;
		m_nextSecs = m_thisSecs + 60*30;
		m_futureSecs = m_nextSecs + 60*30;

		setTableNames(setTableNameByMinute);
		break;
	case MtHour:
		m_thisSecs = now.seconds() - (now.seconds()%3600);
		m_lastSecs = m_thisSecs - 3600;
		m_nextSecs = m_thisSecs + 3600;
		m_futureSecs = m_nextSecs + 3600;

		setTableNames(setTableNameByHour);
		break;
	case Mt2Hours:
		m_thisSecs = now.seconds() - (now.seconds()%(3600*2));
		m_lastSecs = m_thisSecs - 3600*2;
		m_nextSecs = m_thisSecs + 3600*2;
		m_futureSecs = m_nextSecs + 3600*2;

		setTableNames(setTableNameByHour);
		break;
	case Mt3Hours:
		m_thisSecs = now.seconds() - (now.seconds()%(3600*3));
		m_lastSecs = m_thisSecs - 3600*3;
		m_nextSecs = m_thisSecs + 3600*3;
		m_futureSecs = m_nextSecs + 3600*3;

		setTableNames(setTableNameByHour);
		break;
	case Mt4Hours:
		m_thisSecs = now.seconds() - (now.seconds()%(3600*4));
		m_lastSecs = m_thisSecs - 3600*4;
		m_nextSecs = m_thisSecs + 3600*4;
		m_futureSecs = m_nextSecs + 3600*4;

		setTableNames(setTableNameByHour);
		break;
	case Mt6Hours:
		m_thisSecs = now.seconds() - (now.seconds()%(3600*6));
		m_lastSecs = m_thisSecs - 3600*6;
		m_nextSecs = m_thisSecs + 3600*6;
		m_futureSecs = m_nextSecs + 3600*6;

		setTableNames(setTableNameByHour);
		break;
	case Mt8Hours:
		m_thisSecs = now.seconds() - (now.seconds()%(3600*8));
		m_lastSecs = m_thisSecs - 3600*8;
		m_nextSecs = m_thisSecs + 3600*8;
		m_futureSecs = m_nextSecs + 3600*8;

		setTableNames(setTableNameByHour);
		break;
	case Mt12Hours:
		m_thisSecs = now.seconds() - (now.seconds()%(3600*12));
		m_lastSecs = m_thisSecs - 3600*12;
		m_nextSecs = m_thisSecs + 3600*12;
		m_futureSecs = m_nextSecs + 3600*12;

		setTableNames(setTableNameByHour);
		break;
	case MtDay:
		m_thisSecs = dm::CDateTime::today(now).toTimeStamp().seconds();
		m_lastSecs = m_thisSecs - 3600*24;
		m_nextSecs = m_thisSecs + 3600*24;
		m_futureSecs = m_nextSecs + 3600*24;

		setTableNames(setTableNameByDay);
		break;
	case MtMonth:
		m_thisSecs = dm::CDateTime::thisMonth(now).toTimeStamp().seconds();
		m_lastSecs = dm::CDateTime::lastMonth(now).toTimeStamp().seconds();
		m_nextSecs = dm::CDateTime::nextMonth(now).toTimeStamp().seconds();
		m_futureSecs = dm::CDateTime::nextMonth(dm::CDateTime::nextMonth(now)).toTimeStamp().seconds();

		setTableNames(setTableNameByMonth);
		break;
	case MtYear:
		m_thisSecs = dm::CDateTime::thisYear(now).toTimeStamp().seconds();
		m_lastSecs = dm::CDateTime::lastYear(now).toTimeStamp().seconds();
		m_nextSecs = dm::CDateTime::nextYear(now).toTimeStamp().seconds();
		m_futureSecs = dm::CDateTime::nextYear(dm::CDateTime::nextYear(now)).toTimeStamp().seconds();

		setTableNames(setTableNameByYear);
		break;
	default:
		log().warnning(THISMODULE "不支持的存储表类型%d",m_mtType);
		return false;
	}

	// 建表
	if( m_mtType==MtNone ){
		if( !createIfStatus(r_status) ){
			log().error(THISMODULE "创建状态量数据表%s失败",r_status);
			return false;
		}

		if( !createIfDiscrete(r_discrete) ){
			log().error(THISMODULE "创建离散量数据表%s失败",r_discrete);
			return false;
		}

		if( !createIfMeasure(r_measure) ){
			log().error(THISMODULE "创建测量量数据表%s失败",r_measure);
			return false;
		}

		if( !createIfCumulant(r_cumulant) ){
			log().error(THISMODULE "创建累计量数据表%s失败",r_cumulant);
			return false;
		}

		if( !createIfAction(r_action) ){
			log().error(THISMODULE "创建动作数据表%s失败",r_action);
			return false;
		}
	}else{
		// 状态量
		if( !createIfStatus(m_tableThisStatus.c_str()) ){
			log().error(THISMODULE "创建本时段状态量数据表%s失败",m_tableThisStatus.str());
			return false;
		}

		if( !createIfStatus(m_tableLastStatus.c_str()) ){
			log().error(THISMODULE "创建上时段状态量数据表%s失败",m_tableLastStatus.str());
			return false;
		}

		if( !createIfStatus(m_tableNextStatus.c_str()) ){
			log().error(THISMODULE "创建下时段状态量数据表%s失败",m_tableNextStatus.str());
			return false;
		}

		// 离散量
		if( !createIfDiscrete(m_tableThisDiscrete.c_str()) ){
			log().error(THISMODULE "创建本时段离散量数据表%s失败",m_tableThisDiscrete.str());
			return false;
		}

		if( !createIfDiscrete(m_tableLastDiscrete.c_str()) ){
			log().error(THISMODULE "创建上时段离散量数据表%s失败",m_tableLastDiscrete.str());
			return false;
		}

		if( !createIfDiscrete(m_tableNextDiscrete.c_str()) ){
			log().error(THISMODULE "创建下时段离散量数据表%s失败",m_tableNextDiscrete.str());
			return false;
		}

		// 测量量
		if( !createIfMeasure(m_tableThisMeasure.c_str()) ){
			log().error(THISMODULE "创建本时段测量量数据表%s失败",m_tableThisMeasure.str());
			return false;
		}

		if( !createIfMeasure(m_tableLastMeasure.c_str()) ){
			log().error(THISMODULE "创建上时段测量量数据表%s失败",m_tableLastMeasure.str());
			return false;
		}

		if( !createIfMeasure(m_tableNextMeasure.c_str()) ){
			log().error(THISMODULE "创建下时段测量量数据表%s失败",m_tableNextMeasure.str());
			return false;
		}

		// 累计量
		if( !createIfCumulant(m_tableThisCumulant.c_str()) ){
			log().error(THISMODULE "创建本时段累计量数据表%s失败",m_tableThisCumulant.str());
			return false;
		}

		if( !createIfCumulant(m_tableLastCumulant.c_str()) ){
			log().error(THISMODULE "创建上时段累计量数据表%s失败",m_tableLastCumulant.str());
			return false;
		}

		if( !createIfCumulant(m_tableNextCumulant.c_str()) ){
			log().error(THISMODULE "创建下时段累计量数据表%s失败",m_tableNextCumulant.str());
			return false;
		}

		// 动作
		if( !createIfAction(m_tableThisAction.c_str()) ){
			log().error(THISMODULE "创建本时段动作数据表%s失败",m_tableThisAction.str());
			return false;
		}

		if( !createIfAction(m_tableLastAction.c_str()) ){
			log().error(THISMODULE "创建上时段动作数据表%s失败",m_tableLastAction.str());
			return false;
		}

		if( !createIfAction(m_tableNextAction.c_str()) ){
			log().error(THISMODULE "创建下时段动作数据表%s失败",m_tableNextAction.str());
			return false;
		}
	}

	return true;
}

}
}


